package gui;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Label;
import java.awt.Menu;
import java.awt.MenuBar;
import java.awt.Rectangle;
import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.StringTokenizer;
import java.util.concurrent.ExecutionException;

import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
import javax.swing.JToolBar;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
import javax.swing.filechooser.FileSystemView;
import javax.swing.plaf.TabbedPaneUI;
import javax.swing.plaf.basic.BasicTabbedPaneUI;

import framework.AnnuaireCocola;
import framework.classification.library.AbstractClassfication;
import framework.utils.Chrono;
import gui.controller.Controller;
import gui.filter.FileFilterXmi;
import gui.utils.DegradeVerticalPanel;
import gui.utils.JCoolButton;
import gui.utils.JTabbedPaneWithCloseIcons;
import gui.utils.RoundedBorder;

public class ACLGraphics extends JFrame{

	public static String NEW_CLASSIFICATION = "new_classification";
	public static String OPEN_LIBRARY = "open_library";
	public static String NEW_DIRECTORY = "new_directory";
	public static String GENERATE_COMPONENT = "generateComponent";
	public static String GENERATE_INTERFACE = "generateInterface";
	public static String GENERATE_FUNCTION = "generateFunction";
	public static String GENERATE_COMPONENT_LATEX = "generateComponentl";
	public static String GENERATE_INTERFACE_LATEX = "generateInterfacel";
	public static String GENERATE_FUNCTION_LATEX = "generateFunctionl";


	private JMenu run;
	private JMenu generate;
	private JMenu frame;

	private JMenuItem miCreateClassification;

	private HashMap<JMenuItem,SwingWorker> hashItemWork;
	private HashMap<SwingWorker,JMenuItem> hashWorkItem;

	private AnnuaireCocola cocola;
	private Controller controller;

	private JTabbedPane tabbed;
	private JLabel status;


	private JButton bopen;
	private JButton bnewC;
	private JButton bnewD;

	private ViewMetrique metrique;

	//============================================
	//=== Contructeur
	//============================================
	public ACLGraphics(AnnuaireCocola cocola){
		initialiseFrame();
		this.cocola = cocola;
		tabbed.setComponentAt(0,new ViewMetrique(cocola));

		setEtat("ready");
		update();

	}

	public ACLGraphics(String pathxmi){
		initialiseFrame();
		setLibrary(pathxmi,pathxmi.substring(0,pathxmi.indexOf('.')));

	}

	public ACLGraphics(){
		cocola = null;
		initialiseFrame();

	}
	//========================================================

	//========================================================
	//=== Getter
	//========================================================
	public AnnuaireCocola getAnnuaireCocola(){return cocola;}
	public Controller getController(){return controller;}
	//=========================================================

	private void initialiseFrame(){
		hashItemWork = new HashMap<JMenuItem, SwingWorker>();
		hashWorkItem = new HashMap<SwingWorker, JMenuItem>();
		controller = new Controller(this);
		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		this.setJMenuBar(createMenuBar());
		this.setContentPane(createComponent());
		this.setSize(700,700);
		this.setVisible(true);

	}

	private JComponent createComponent(){
		JPanel panel = new JPanel(new BorderLayout());
		panel.add(createToolBar(),BorderLayout.NORTH);
		panel.setBackground(Color.WHITE);
		tabbed = new JTabbedPaneWithCloseIcons();tabbed.setUI(new BasicTabbedPaneUI());
		tabbed.add("metrique",new JPanel());
		tabbed.addMouseListener(controller);
		panel.add(tabbed);
		return panel;
	}

	private JMenuBar createMenuBar(){
		JMenuBar menu = new JMenuBar();

		JMenu file = new JMenu("File");
		miCreateClassification = new JMenuItem("Create Classification");
		miCreateClassification.setActionCommand(this.NEW_CLASSIFICATION);
		miCreateClassification.addActionListener(controller);
		miCreateClassification.setEnabled(false);
		JMenuItem milibrary = new JMenuItem("New Library");
		milibrary.setActionCommand(this.NEW_DIRECTORY);
		milibrary.addActionListener(controller);
		JMenuItem miopen = new JMenuItem("Open Library");
		miopen.setActionCommand(this.OPEN_LIBRARY);
		miopen.addActionListener(controller);
		file.add(milibrary);
		file.add(miopen);
		file.add(miCreateClassification);

		JMenu about = new JMenu("About");
		run = new JMenu("Run");
		generate = new JMenu("Generate");



		JMenuItem gComponent = new JMenuItem("Generate Components Images");
		gComponent.setActionCommand(GENERATE_COMPONENT);gComponent.addActionListener(controller);
		JMenuItem gInterface = new JMenuItem("Generate Interfaces Images");
		gInterface.setActionCommand(GENERATE_INTERFACE);gInterface.addActionListener(controller);
		JMenuItem gFunction = new JMenuItem("Generate Functions Images");
		gFunction.setActionCommand(GENERATE_FUNCTION);gFunction.addActionListener(controller);

		JMenuItem gComponentl = new JMenuItem("Generate Components Latex");
		gComponentl.setActionCommand(GENERATE_COMPONENT_LATEX);gComponentl.addActionListener(controller);
		JMenuItem gInterfacel = new JMenuItem("Generate Interfaces Latex");
		gInterfacel.setActionCommand(GENERATE_INTERFACE_LATEX);gInterfacel.addActionListener(controller);
		JMenuItem gFunctionl = new JMenuItem("Generate Functions Latex");
		gFunctionl.setActionCommand(GENERATE_FUNCTION_LATEX);gFunctionl.addActionListener(controller);


		generate.add(gComponent);generate.add(gInterface);generate.add(gFunction);
		generate.addSeparator();
		generate.add(gComponentl);generate.add(gInterfacel);generate.add(gFunctionl);
		generate.setEnabled(false);


		frame = new JMenu("Frame");
		JMenuItem micasc = new JMenuItem("Cascade");
		micasc.setActionCommand(ViewDirectory.CASCADE);micasc.addActionListener(controller);
		JMenuItem mialign = new JMenuItem("Align");
		mialign.setActionCommand(ViewDirectory.ALIGN);mialign.addActionListener(controller);
		JMenuItem mireduced = new JMenuItem("All Reduced");
		mireduced.setActionCommand(ViewDirectory.ALL_REDUCED);mireduced.addActionListener(controller);
		frame.add(micasc);frame.add(mialign);frame.add(mireduced);
		frame.setEnabled(false);


		menu.add(file);
		menu.add(generate);
		menu.add(run);
		menu.add(frame);
		menu.add(about);
		return menu;
	}
	private JPanel createToolBar(){
		JPanel panel = new DegradeVerticalPanel(new Color(50,50,50),new Color(0,0,0));
		panel.setLayout(new BorderLayout());
		panel.setMinimumSize(new Dimension(1000,60));
		panel.setMaximumSize(new Dimension(1000,60));
		panel.setPreferredSize(new Dimension(1000,60));

		ImageIcon image = new ImageIcon("icons/ACLIcon.png");

		status = new JLabel("librairy: nothing");

		status.setForeground(Color.WHITE);
		status.setMinimumSize(new Dimension(300,40));
		status.setPreferredSize(new Dimension(300,40));
		status.setMaximumSize(new Dimension(300,40));

		bnewC = createButton("create classification",new Color(0,0,0),new Color(0,150,193), NEW_CLASSIFICATION,false);
		bnewD = createButton("new directory",new Color(0,0,0),new Color(0,150,193),NEW_DIRECTORY,true);
		bopen = createButton("open library",new Color(0,0,0),new Color(0,150,193),OPEN_LIBRARY,true);


		Box hbox = Box.createHorizontalBox();
		hbox.add(Box.createHorizontalStrut(15));
		hbox.add(new JLabel(image));
		hbox.add(Box.createHorizontalGlue());
		hbox.add(bnewD);
		hbox.add(Box.createHorizontalStrut(40));
		hbox.add(bopen);
		hbox.add(Box.createHorizontalStrut(5));
		hbox.add(bnewC);
		hbox.add(Box.createHorizontalGlue());
		hbox.add(status);
		panel.add(hbox,BorderLayout.CENTER);
		return panel;
	}

	private JButton createButton(String name,Color colori, Color colors,String action,Boolean enabled){
		JCoolButton b = new JCoolButton(name,colori,colors);
		b.setEnabled(enabled);
		b.setActionCommand(action);
		b.addActionListener(controller);
		return b;
	}

	public void addrunning(String s,SwingWorker w){
		JMenuItem item = new JMenuItem(s);
		item.setIcon(new ImageIcon("icons/closedIcon.png"));
		item.setActionCommand("run");
		item.addActionListener(controller);
		hashItemWork.put(item,w);
		hashWorkItem.put(w,item);
		run.add(item);
	}

	public void stopRunning(JMenuItem item){
		SwingWorker work = hashItemWork.get(item);
		work.cancel(true);
		run.remove(item);
		hashItemWork.remove(item);
		hashWorkItem.remove(work);

		if (hashItemWork.isEmpty())
			setEtat("ready");
		else setEtat(hashItemWork.keySet().iterator().next().getText()+" running ...");

	}
	public void stopRunning(SwingWorker work){
		JMenuItem item = hashWorkItem.get(work);
		run.remove(item);
		hashItemWork.remove(item);
		hashWorkItem.remove(work);

	}
	public void addClassification(AbstractClassfication cl){
		ViewDirectory vv = new ViewDirectory(cl,controller);
		tabbed.add(cl.getLatticeGeneration()+" "+cl.getmode()+" "+cl.getCocola().getName(),vv);
		tabbed.setSelectedIndex(tabbed.getTabCount()-1);
	}

	//args 1 :: mode classification
	//args 2 :: level pour smart
	//args 3 :: ordered pour fast
	//args 4 :: lattice generation
	public void addClassification(ArrayList<Object> args){

		final Chrono c1 = new Chrono();
		c1.start();

		//argument
		Integer mode = (Integer) args.get(0);
		final Integer level = (Integer) args.get(1);
		final Boolean ordered = (Boolean) args.get(2);
		final String lattice = (String) args.get(3);



		SwingWorker<AbstractClassfication,Void> worker = null;



		if (mode == AnnuaireCocola.COMPLETE){

			worker = new SwingWorker<AbstractClassfication,Void>() {
				protected AbstractClassfication doInBackground() throws Exception {
					c1.start();
					AbstractClassfication cl = cocola.createCompleteClassification(lattice);
					return cl;
				}
				public void done(){
					c1.stop();
					if (!isCancelled()){
						try {
							AbstractClassfication cl = (AbstractClassfication) get();
							addClassification(cl);
							setEtat("classification completed in "+(float)c1.getMilliSec()*Math.pow(10,-3)+" s");
							update();
						} catch (InterruptedException e) {
						
						} catch (ExecutionException e) {
							e.printStackTrace();
							setEtat("classification failed");
						}
						stopRunning(this);
					}

				}
			};
			setEtat("Complete "+lattice+" running ...");
			addrunning("Complete "+lattice,worker);
			worker.execute();






		}
		else if (mode == AnnuaireCocola.SMART){

			worker = new SwingWorker<AbstractClassfication,Void>() {
				protected AbstractClassfication doInBackground() throws Exception {
					c1.start();
					AbstractClassfication cl = cocola.createSmartClassification(level,lattice);
					return cl;
				}
				public void done(){
					c1.stop();
					if (!isCancelled()){
						try {
							AbstractClassfication cl = (AbstractClassfication) get();
							addClassification(cl);
							setEtat("classification completed in "+(float)c1.getMilliSec()*Math.pow(10,-3)+" s");
							update();
						} catch (InterruptedException e) {} catch (ExecutionException e) {
							e.printStackTrace();
							setEtat("classification failed");
						}
						stopRunning(this);
					}
				}
			};


			addrunning("Smart "+lattice,worker);
			setEtat("Smart "+lattice+" running ...");
			worker.execute();



		}
		else if (mode == AnnuaireCocola.FAST){

			worker = new SwingWorker<AbstractClassfication,Void>() {
				protected AbstractClassfication doInBackground() throws Exception {
					c1.start();

					System.out.println(ordered);
					AbstractClassfication 	cl = cocola.createFastClassification(ordered,lattice);
					return cl;
				}
				public void done(){
					c1.stop();
					if (!isCancelled()){
						try {
							AbstractClassfication cl = (AbstractClassfication) get();
							addClassification(cl);
							setEtat("classification completed in "+(float)c1.getMilliSec()*Math.pow(10,-3)+" s");
							update();
						} catch (InterruptedException e) {} catch (ExecutionException e) {
							e.printStackTrace();
							setEtat("classification failed");
						}
						stopRunning(this);
					}
				}
			};

			setEtat("Fast "+lattice+" running ...");
			addrunning("Fast "+lattice,worker);
			worker.execute();

		}



	}

	public ViewDirectory getCurrentClassification(){

		if (tabbed.getSelectedIndex() != 0){
			ViewDirectory vv = (ViewDirectory) tabbed.getSelectedComponent();

			return vv;
		}
		return null;
	}

	public void setEtat(String etat){
		status.setText("<html> <u>Library</u> : <i>"+cocola.getName()+"</i><br/>"+"<u>Etat</u> : <i>"+etat+"</i></html>");
		status.updateUI();
	}

	public void setLibrary(final String path,final String out){

		SwingWorker	worker = new SwingWorker<AnnuaireCocola,Void>() {
			protected AnnuaireCocola doInBackground() throws Exception {
				AnnuaireCocola cocola = new AnnuaireCocola(path,out);
				return cocola;
			}
			public void done(){

				if (!isCancelled()){
					try {

						cocola = get();
						tabbed.setComponentAt(0,new ViewMetrique(cocola));

						setEtat("ready");
						update();

					} catch (InterruptedException e) {} catch (ExecutionException e) {}
					stopRunning(this);
				}
			}
		};
		worker.execute();
		status.setText("<html> <u>Library</u> :<i> load "+out+"</i></html>");
		addrunning("load library "+out,worker);




	}

	public void generate_Components(ArrayList<String> args){
		if (args != null){
			ViewDirectory vv = (ViewDirectory) tabbed.getSelectedComponent();
			vv.getAbstractClassification().generateComponentsImage(args.get(0), args.get(1));
		}

	}
	public void generate_Interfaces(ArrayList<String> args){
		if (args != null){
			ViewDirectory vv = (ViewDirectory) tabbed.getSelectedComponent();
			vv.getAbstractClassification().generateInterfacesImage(args.get(0), args.get(1));
		}
	}
	public void generate_Fucntions(ArrayList<String> args){
		if (args != null){
			ViewDirectory vv = (ViewDirectory) tabbed.getSelectedComponent();
			vv.getAbstractClassification().generateFunctionsImage(args.get(0), args.get(1));
		}
	}

	
	public void generate_Components_Latex(ArrayList<String> args){
		if (args != null){
			ViewDirectory vv = (ViewDirectory) tabbed.getSelectedComponent();
			vv.getAbstractClassification().generateComponentsLatex(args.get(0));
		}

	}
	public void generate_Interfaces_Latex(ArrayList<String> args){
		if (args != null){
			ViewDirectory vv = (ViewDirectory) tabbed.getSelectedComponent();
			vv.getAbstractClassification().generateInterfacesLatex(args.get(0));
		}
	}
	public void generate_Fucntions_Latex(ArrayList<String> args){
		if (args != null){
			ViewDirectory vv = (ViewDirectory) tabbed.getSelectedComponent();
			vv.getAbstractClassification().generateFunctionsLatex(args.get(0));
		}
	}
	
	public void newLibrary(String url){
		
		if (url != null){
			StringTokenizer tok = new StringTokenizer(url,"/");
			while (tok.countTokens() != 1){
				tok.nextToken();
			}
			String out = tok.nextToken();
			setLibrary(url,out.substring(0,out.indexOf('.')));
		}
	}

	public void openLibrary(){

		File file = null;
		JFileChooser chooser = new JFileChooser();

		FileSystemView vueSytem = FileSystemView.getFileSystemView();
		File home = vueSytem.getHomeDirectory();
		chooser.setCurrentDirectory(home);
		chooser.setFileFilter(new FileFilterXmi());
		int rep = chooser.showOpenDialog(this);
		if (rep == JFileChooser.APPROVE_OPTION)	
		{
			try
			{
				file = chooser.getSelectedFile();
				String url = file.getAbsolutePath();
				String preout = url.substring(0,url.lastIndexOf('.'));
				String out = "";
				for (int i=preout.length()-1;i>=0;i--){
					
					if ((preout.charAt(i) == '/')||(preout.charAt(i) == '\\')){
						break;
					}else out = preout.charAt(i) + out;
						
				}
			
				setLibrary(file.getAbsolutePath(),out);
			}
			catch (NullPointerException e){}catch (Exception e) {}
		}

	}


	public void update(){
		if (tabbed.getSelectedIndex() != 0) {
			generate.setEnabled(true);
			frame.setEnabled(true);
		}
		else {
			generate.setEnabled(false);
			frame.setEnabled(false);
		}

		if (cocola == null){
			miCreateClassification.setEnabled(false);
			bnewC.setEnabled(false);
		}
		else{
			miCreateClassification.setEnabled(true);
			bnewC.setEnabled(true);
		}

	}
}
